﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
using Microsoft.Devices.Sensors;
using Microsoft.Xna.Framework;
using System.Windows.Threading;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using Microsoft.Phone.Net.NetworkInformation;
using Microsoft.Xna.Framework.Input.Touch;
using System.Windows.Input;
using Windows.Networking.Connectivity;


namespace ASCM_WpControlApp
{
    public partial class MainPage : PhoneApplicationPage
    {
        #region definitons


        Server server;


        // Readings accelReading = new Readings();
        DateTimeOffset lastUpdateTime = DateTimeOffset.MinValue;


        private float calibratedX;
        private float calibratedY;
        private float calibratedZ;


        #endregion

        //  Motion motion;
        System.Windows.Point abs_slider1;
        System.Windows.Point abs_slider2;

        Readings reading;
        Rectangle rect1;
        Rectangle rect2;

        Accelerometer sensor_acc;
        Motion motion;

        public MainPage()
        {


            InitializeComponent();
            reading = new Readings();

            Touch.FrameReported += Touch_sensed;

            server = new Server();
            server.on_request += new Server.OnRequest(Respond);
            textBlockData.Text = "IP: " + AddressIP();
            //  server.on_error += new Server.OnError(ShowError);


            //TODO: občasni problemi, ko zaženemo motion, server ne sprejema povezav, slab ping, uporabi accelometer
            if (false)
            {
                motion = new Motion();
                motion.TimeBetweenUpdates = TimeSpan.FromMilliseconds(20);
                motion.CurrentValueChanged += new EventHandler<SensorReadingEventArgs<MotionReading>>(OnSensorReadingChangedMotion); ;
                motion.Start();
            }

            if (Gyroscope.IsSupported)
            {
                Gyroscope sensor_gyro = new Gyroscope();
                sensor_gyro.CurrentValueChanged += gyro_CurrentValueChanged;
                sensor_gyro.TimeBetweenUpdates = TimeSpan.FromMilliseconds(20);
                sensor_gyro.Start();
                z_slider.Visibility = Visibility.Collapsed;//skrij kontrolo
            }
            else
            {
                sensor_acc = new Accelerometer();
                sensor_acc.CurrentValueChanged += accelerometer_CurrentValueChanged;
                sensor_acc.TimeBetweenUpdates = TimeSpan.FromMilliseconds(20);
                sensor_acc.Start();
            }


        }

        private void accelerometer_CurrentValueChanged(object sender, SensorReadingEventArgs<AccelerometerReading> e)
        {

            Dispatcher.BeginInvoke(() =>
            {
                double x = ScaleRange(e.SensorReading.Acceleration.X, -1, 1, 125, -125);
                double y = ScaleRange(e.SensorReading.Acceleration.Y, -1, 1, 125, -125);
                circle.Margin = new Thickness(x, y, -0, 0);
                //izpiši vrednosti na zaslonu..
                // textBlockData.Text = string.Format("X:{0} Y:{1} Z:{2} T:{3}", String.Format(reading.X.ToString("000")), String.Format(reading.Y.ToString("000")), String.Format(reading.Z.ToString("000")), String.Format(reading.Throttle.ToString("000")));
            });

        }

        private void gyro_CurrentValueChanged(object sender, SensorReadingEventArgs<GyroscopeReading> e)
        {
            //test
            reading.X = (int)ScaleRange((e.SensorReading.RotationRate.X * (180 / Math.PI)), -90, 90, 0, 999);
            reading.Y = (int)ScaleRange((e.SensorReading.RotationRate.Y * (180 / Math.PI)), -180, 180, 0, 999);
            reading.Z = (int)ScaleRange((e.SensorReading.RotationRate.Z * (180 / Math.PI)), -180, 180, 0, 999);

        }


        private void ShowError(bool fatal, string msg)
        {
            Dispatcher.BeginInvoke(() =>
            {
                textBlockData.Text = String.Format(msg);
            });
        }

        public void Respond(ref  Readings reading)
        {
            reading.X = (int)ScaleRange(sensor_acc.CurrentValue.Acceleration.X, -1, 1, 0, 999);
            reading.Y = (int)ScaleRange(sensor_acc.CurrentValue.Acceleration.Y, -1, 1, 0, 999);
            reading.Throttle = this.reading.Throttle;

            //  reading.X = (int)ScaleRange(motion.CurrentValue.Gravity.X, -1, 1, 0, 999);
            // reading.Y = (int)ScaleRange(motion.CurrentValue.Gravity.Y, -1, 1, 0, 999);

            //if (!Gyroscope.IsSupported)
            //    reading.Z = throttle;
            //else
            //    reading.Z = (int)ScaleRange(sensor_acc.CurrentValue.Acceleration.X, -1, 1, 0, 999);

        }


        private void Slider_ValueChanged_1(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            reading.Throttle = (int)e.NewValue;

        }
        private void z_slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
              reading.Z = (int)e.NewValue;
        }
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            calibratedX = sensor_acc.CurrentValue.Acceleration.X;
            calibratedY = sensor_acc.CurrentValue.Acceleration.Y;
            textBlockData.Text = AddressIP();
            //server.testCancel();
        }

        public String AddressIP()
        {
            List<string> ipAddresses = new List<string>();

            var hostnames = NetworkInformation.GetHostNames();

            foreach (var hn in hostnames)
            {
                if (hn.IPInformation != null)
                {
                    string ipAddress = hn.DisplayName;
                    ipAddresses.Add(ipAddress);
                }
            }

            IPAddress address = IPAddress.Parse(ipAddresses[0]);
            return address.ToString();
        }


        //vrednost, min vhodna, max vhodna, min izhodna, max izhodna vrednost
        public double ScaleRange(double value, double aMin, double aMax, double bMin, double bMax)
        {
            if (value > aMax)
                return bMax;

            if (value < aMin)
                return bMin;

            return bMin + (bMax - bMin) * ((value - aMin) / (aMax - aMin));
        }



        #region Utišaj evente sliderjev

        private void throttle_slider_ManipulationStarted(object sender, ManipulationStartedEventArgs e)
        {
            e.Handled = true;
        }

        private void throttle_slider_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
        {
            e.Handled = true;
        }

        private void z_slider_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
        {
            e.Handled = true;
        }

        private void z_slider_ManipulationStarted(object sender, ManipulationStartedEventArgs e)
        {
            e.Handled = true;
        }

        #endregion

        private void OnSensorReadingChangedMotion(object sender, SensorReadingEventArgs<MotionReading> e)
        {

            // reading.X = (int)ScaleRange(e.SensorReading.Gravity.X, -1, 1, 0, 999);
            //  reading.Y = (int)ScaleRange(e.SensorReading.Gravity.Y, -1, 1, 0, 999);

            reading.X = (int)ScaleRange((e.SensorReading.Attitude.Roll * (180 / Math.PI)), -90, 90, 0, 999);
            reading.Y = (int)ScaleRange((e.SensorReading.Attitude.Pitch * (180 / Math.PI)), -180, 180, 0, 999);
            reading.Z = (int)ScaleRange((e.SensorReading.Attitude.Roll * (180 / Math.PI)), -180, 180, 0, 999);

        }

        void Touch_sensed(object sender, TouchFrameEventArgs e)
        {

            //dobi okvirje okoli kontrol
            var transform = throttle_slider.TransformToVisual(Application.Current.RootVisual);
            abs_slider1 = transform.Transform(new System.Windows.Point(0, 0));

            transform = z_slider.TransformToVisual(Application.Current.RootVisual);
            abs_slider2 = transform.Transform(new System.Windows.Point(0, 0));

            rect1 = new Rectangle((int)abs_slider1.X, (int)abs_slider1.Y,
               (int)throttle_slider.ActualWidth, (int)throttle_slider.ActualHeight);

            rect2 = new Rectangle(80, (int)abs_slider2.Y, (int)z_slider.Height, (int)z_slider.Width);

            TouchPointCollection touchPoints = e.GetTouchPoints(null);

            foreach (TouchPoint tp in touchPoints)
            {
                if (tp.Action == TouchAction.Move)
                {
                    reading.X = (int)tp.Position.Y;


                    Microsoft.Xna.Framework.Point tempPoint = new Microsoft.Xna.Framework.Point((int)tp.Position.X, (int)tp.Position.Y);

                    if (rect1.Contains(tempPoint))
                    {
                        //ročno spremeni vrednosti
                        throttle_slider.Value = ((tp.Position.X - rect2.X) / throttle_slider.ActualWidth) * 999;
                    }

                    if (rect2.Contains(tempPoint))
                    {
                        var tmp = (tp.Position.Y - rect2.Y) / rect2.Height;

                        z_slider.Value = ((tp.Position.Y - rect2.Y) / rect2.Height) * 999;

                    }

                }

            }



        }


    }
}